\documentclass{ctexart}

%\usepackage{ctex}
\usepackage{graphicx}
\usepackage{float}
\usepackage{datetime}
%\usepackage{minipage}

\begin{document}
\section{socket常用函数}\label{socketux5e38ux7528ux51fdux6570}

\subsection{bind函数}\label{bindux51fdux6570}

bind函数将一个socket绑定一个名字(有点难以理解)



当使用socket函数创建套接字时，它存在于名称空间(地址族)，但没有分配给它的地址。bind将由addr指定的地址到文件de引用的套接字sockfd。addrlen指定地址结构体的大小。该结构体由不同的地址族规定。

正常返回0，否则返回-1,error代表错误。下面是值得注意的错误码。


\begin{minipage}[b]{\linewidth}\raggedright
error
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
注意
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
EADDRINUSE & /proc/sys/net/ipv4/ip\_local\_port\_range
范围内部的端口用尽了需要检查是不是有句柄泄漏 \\
ELOOP &
当绑定本地unix域的时候，解析路径次数超限,可能存在符号链接循环或者符号链接层数过多 \\
\end{longtable}

\subsection{listen函数}\label{listenux51fdux6570}

listen函数为socket分配一个监听队列。

\begin{Shaded}
\begin{Highlighting}[]
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/types.h\textgreater{}}\PreprocessorTok{          }\CommentTok{/* See NOTES */}
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/socket.h\textgreater{}}
\DataTypeTok{int}\NormalTok{ listen}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \DataTypeTok{int}\NormalTok{ backlog}\OperatorTok{);}
\end{Highlighting}
\end{Shaded}

注意，sockfd必须指向一个SOCK\_STREAM或SOCK\_SEQPACKET。
backlog参数指明sockfd上最多允许多少个处于establish状态的连接。如果满了，客户端会收到无法链接报错，同时如果底层协议允许，重传请求。
最大的半连接队列长度使用/proc/sys/net/ipv4/tcp\_max\_syn\_backlog来指明。

正常返回0，否则返回-1,error代表错误。

\subsection{accept函数}\label{acceptux51fdux6570}

accept函数接收一个链接并返回一个用于此链接通信的socket

\begin{Shaded}
\begin{Highlighting}[]
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/types.h\textgreater{}}\PreprocessorTok{          }\CommentTok{/* See NOTES */}
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/socket.h\textgreater{}}
\DataTypeTok{int}\NormalTok{ accept}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \KeywordTok{struct}\NormalTok{ sockaddr }\OperatorTok{*}\NormalTok{addr}\OperatorTok{,} \DataTypeTok{socklen\_t} \OperatorTok{*}\NormalTok{addrlen}\OperatorTok{);}

\PreprocessorTok{\#define }\OtherTok{\_GNU\_SOURCE}\PreprocessorTok{             }\CommentTok{/* See feature\_test\_macros(7) */}
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/socket.h\textgreater{}}
\DataTypeTok{int}\NormalTok{ accept4}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \KeywordTok{struct}\NormalTok{ sockaddr }\OperatorTok{*}\NormalTok{addr}\OperatorTok{,}\DataTypeTok{socklen\_t} \OperatorTok{*}\NormalTok{addrlen}\OperatorTok{,} \DataTypeTok{int}\NormalTok{ flags}\OperatorTok{);}
\end{Highlighting}
\end{Shaded}

accept函数用于基于链接的socket被动端接收一个连接(SOCK\_STREAM/SOCK\_SEQPACKET)。且这个socket处于bind以及listen后的状态。
此函数会阻塞，如果没有置非阻塞状态。

\begin{longtable}[]{@{}
  >{\raggedright\arraybackslash}p{(\columnwidth - 2\tabcolsep) * \real{0.0656}}
  >{\raggedright\arraybackslash}p{(\columnwidth - 2\tabcolsep) * \real{0.9344}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
error
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
注意
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
EAGAIN/EWOULDBLOCK & 非阻塞的Socket上没有连接到来，需要等待 \\
EMFILE & 进程的文件描述符超限 \\
ENFILE & 系统的文件描述符超限 \\
EPERM & 防火墙限制 \\
\end{longtable}

注意，accept即使在epoll等复用器上返回可读，accpet调用也可能会阻塞。因为可能连接在accept前就失败了或者已经被另一个线程拿走了。
所以一般accpet都是非阻塞的。

\subsection{connect函数}\label{connectux51fdux6570}

connect函数发起一个连接到服务端Socket。

\begin{Shaded}
\begin{Highlighting}[]
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/types.h\textgreater{}}\PreprocessorTok{          }\CommentTok{/* See NOTES */}
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/socket.h\textgreater{}}
\DataTypeTok{int} \FunctionTok{connect}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \AttributeTok{const} \KeywordTok{struct}\NormalTok{ sockaddr }\OperatorTok{*}\NormalTok{addr}\OperatorTok{,}\DataTypeTok{socklen\_t}\NormalTok{ addrlen}\OperatorTok{);}
\end{Highlighting}
\end{Shaded}

如果sockfd指向一个数据报协议，那么connect实际指定了默认的发报目的地，同时也指明了只接收给定地址的报文。
如果是流式协议，那么就是开始创建连接。

此函数在失败后需要销毁socket,重新创建socket并connect。

\subsection{send与recv}\label{sendux4e0erecv}

send/sendto/sendmsg向socket发送信息。

\begin{Shaded}
\begin{Highlighting}[]
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/types.h\textgreater{}}
\PreprocessorTok{\#include }\ImportTok{\textless{}sys/socket.h\textgreater{}}

\DataTypeTok{ssize\_t}\NormalTok{ send}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \AttributeTok{const} \DataTypeTok{void} \OperatorTok{*}\NormalTok{buf}\OperatorTok{,} \DataTypeTok{size\_t}\NormalTok{ len}\OperatorTok{,} \DataTypeTok{int}\NormalTok{ flags}\OperatorTok{);}
\DataTypeTok{ssize\_t}\NormalTok{ sendto}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \AttributeTok{const} \DataTypeTok{void} \OperatorTok{*}\NormalTok{buf}\OperatorTok{,} \DataTypeTok{size\_t}\NormalTok{ len}\OperatorTok{,} \DataTypeTok{int}\NormalTok{ flags}\OperatorTok{,}\AttributeTok{const} \KeywordTok{struct}\NormalTok{ sockaddr }\OperatorTok{*}\NormalTok{dest\_addr}\OperatorTok{,} \DataTypeTok{socklen\_t}\NormalTok{ addrlen}\OperatorTok{);}
\DataTypeTok{ssize\_t}\NormalTok{ sendmsg}\OperatorTok{(}\DataTypeTok{int}\NormalTok{ sockfd}\OperatorTok{,} \AttributeTok{const} \KeywordTok{struct}\NormalTok{ msghdr }\OperatorTok{*}\NormalTok{msg}\OperatorTok{,} \DataTypeTok{int}\NormalTok{ flags}\OperatorTok{);}
\end{Highlighting}
\end{Shaded}

\subsection{close/shutdown函数}\label{closeshutdownux51fdux6570}

\subsection{epoll系统调用}\label{epollux7cfbux7edfux8c03ux7528}

epoll监视多个文件描述符，看看是否可以在其中任何一个上进行I/O。epoll同时支持ET以及LT模式，前者仅在有数据就绪时通知一次，后续除非数据处理完毕，又有数据就绪，否则不会再通知。后者有数据未处理就会一直给通知。

对于ET以及LT,均推荐使用非阻塞式IO。阻塞式IO会导致一直在一个socket上阻塞，后续的socket数据无法及时处理。非阻塞IO一直收数据等待返回EAGIN、EWOULDBLOCK即可停止。

\end{document}
